package dart

class Game {

	List playerGames = new ArrayList()
	Date date = new Date()
	Integer status = IN_PROGRESS
	Integer currentRound = 1
	Integer currentPlayer = 0

	Boolean countDown
	Float startingScore
	Float endingScore
	Float scoreLimit

	Boolean forceAllThrows
	Float bounceBack

	Float harshScale = 0.0
	Boolean harshAndMainPenalties = true

	static hasMany = [playerGames: PlayerGame]
	static constraints = {
		playerGames(minSize: 1)
		bounceBack(nullable: true)
		scoreLimit(nullable: true)
	}

	static Integer IN_PROGRESS = 1;
	static Integer FINISHING = 2;
	static Integer COMPLETED = 3;

	public Float harshPenalty(Float currentScore){
		Float harshPenalty = (startingScore - currentScore) * (harshScale)
		println("($startingScore - $currentScore ) * $harshScale = $harshPenalty [${Util.roundToValidScore(harshPenalty)}]")
		return Util.roundToValidScore(harshPenalty)
	}

	public nextPlayer = {Float endScore ->
		if (isWinningScore(endScore)) {
			status = FINISHING;
		}
		currentPlayer = (currentPlayer + 1) % playerGames.size()
		if (currentPlayer == 0) {
			if (status == FINISHING)
				endGame();
			currentRound++
		}
	}

	public endGame = {
		status = COMPLETED;
		List winners = [];
		playerGames.each {PlayerGame playerGame ->
			if (isWinningScore(playerGame.currentScore()))
				winners << playerGame
			else
				playerGame.status = PlayerGame.LOST
		}

		winners.each {PlayerGame playerGame ->
			playerGame.status = (winners.size() == 1 ? PlayerGame.WON : PlayerGame.TIE)
		}
	}

	public List scoreTable(){
		List table = []
		playerGames.each{ PlayerGame playerGame->
			List scores = []
			Float score = startingScore;
			scores << score;
			playerGame.rounds.each{ Round round ->
				score = round.getScore(score);
				scores << score;
			}
			table << scores;
		}
		return table
	}

	public Boolean isWinningScore(Float score) {
		return (countDown ? score <= endingScore : score >= endingScore)
	}

	public Boolean isBust(Float score) {
		return (bounceBack == null && (countDown ? score < endingScore : score > endingScore))
	}

	public Boolean isBeyondLimit(Float score) {
		return (scoreLimit != null && (countDown ? score > scoreLimit : score < scoreLimit));
	}

	public Boolean isBeyondBounceBack(Float score) {
		return (bounceBack != null && (countDown ? score < bounceBack : score > bounceBack))
	}
}